package com.googlecode.restitory.api;

import java.io.Reader;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonNull;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonParser;
import com.google.gson.JsonPrimitive;

public class JsonHelper {

	public static JsonElement parse(Reader reader) {
		JsonParser parser = new JsonParser();
		JsonElement ret = parser.parse(reader);
		return ret;
	}

	public static JsonElement parse(String json) {
		JsonParser parser = new JsonParser();
		JsonElement ret = parser.parse(json);
		return ret;
	}

	public static Object jsonToBasicObject(JsonElement value) {
		if (value == null || value.isJsonNull()) {
			return null;
		}
		if (value.isJsonPrimitive()) {
			JsonPrimitive primitive = (JsonPrimitive) value;
			if (primitive.isBoolean()) {
				return primitive.getAsBoolean();
			}
			if (primitive.isNumber()) {
				return primitive.getAsNumber();
			}
			if (primitive.isString()) {
				return primitive.getAsString();
			}
		}
		if (value.isJsonArray()) {
			JsonArray array = (JsonArray) value;
			Iterator<JsonElement> it = array.iterator();
			List<Object> ret = new ArrayList<Object>();
			while (it.hasNext()) {
				JsonElement child = it.next();
				Object v = jsonToBasicObject(child);
				ret.add(v);
			}
			return ret;
		}
		throw new JsonParseException("unsupported: " + value);
	}

	public static JsonObject uncontrol(JsonElement json) {
		if (json == null || !json.isJsonObject()) {
			throw new RuntimeException("impossible");
		}
		JsonObject obj = (JsonObject) json;
		Set<Entry<String, JsonElement>> set = obj.entrySet();
		set = new HashSet<Map.Entry<String, JsonElement>>(set);
		for (Entry<String, JsonElement> entry : set) {
			String name = entry.getKey();
			if (name.startsWith("_")) {
				obj.remove(name);
			}
		}
		return obj;
	}

	public static <T extends Enum<T>> T jsonToEnum(Class<T> clazz,
			JsonElement json, T def) {
		String value = (String) jsonToBasicObject(json);
		if (value == null) {
			return def;
		}
		return Enum.valueOf(clazz, value.toUpperCase());
	}

	@SuppressWarnings("unchecked")
	public static JsonElement createBasic(Object value) {
		if (value == null) {
			return new JsonNull();
		}
		if (value instanceof Boolean) {
			return new JsonPrimitive((Boolean) value);
		}
		if (value instanceof Number) {
			return new JsonPrimitive((Number) value);
		}
		if (value instanceof String) {
			return new JsonPrimitive((String) value);
		}
		if (value instanceof Iterable) {
			Iterable<Object> it = (Iterable<Object>) value;
			JsonArray ret = new JsonArray();
			for (Object object : it) {
				ret.add(createBasic(object));
			}
			return ret;
		}
		throw new UnsupportedOperationException("unsupported type: " + value);
	}
}
